package com.study.ju.web.Filter;

import com.study.ju.util.EscapeURLDecoder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * <p>防止xss攻击 sql注入</p>
 *
 * @version v 0.1 2023/4/11 19:44
 */
public class XssFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(XssFilter.class);
    protected static String EMPTY = "";

    /**
     * 引导页
     */
    protected static String INDEX_VIEW_PAGE = "/index";
    protected FilterConfig filterConfig;
    /**
     * 非法字符
     */
    String DEFAULT_ILLEGAL_CHAR_CHECK = "document.cookie|href|script|select |select/|select\\(|select\\*|insert |insert/|insert\\(|insert\\*|update |update/|update\\(|update\\*|delete |delete/|delete\\(|delete\\*|truncate |truncate/|truncate\\(|truncate\\*|exec |exec/|exec\\(|exec\\*|drop |drop/|drop\\(|drop\\*";
    private Pattern PATTERN = Pattern.compile(DEFAULT_ILLEGAL_CHAR_CHECK);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        //web.xml中的参数  <param-name>illegal_char_check</param-name>
        String illegal_char_check = filterConfig.getInitParameter("illegal_char_check");
        if (!StringUtils.isBlank(illegal_char_check)) {
            try {
                PATTERN = Pattern.compile(illegal_char_check);
            } catch (Exception ex) {
                PATTERN = Pattern.compile(DEFAULT_ILLEGAL_CHAR_CHECK);
            }
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        String query = req.getQueryString();
        try {
            if (!StringUtils.isBlank(query) && (PATTERN.matcher(EscapeURLDecoder.decode(query.toLowerCase())).find())) {
                logger.error("输入的url和参数含有非法或系统不能接受字符,query={}", query);

                if (isAjax(req)) {
                    resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                    resp.addHeader("Ajax-Response-Redirect", getRequestHost(req) + INDEX_VIEW_PAGE);
                } else {
                    sendRedirect(resp, getRequestHost(req) + INDEX_VIEW_PAGE);
                }
            } else {
                XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
                chain.doFilter(xssRequest, response);
            }
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    @Override
    public void destroy() {

    }

    /**
     * 判断是否是ajax请求
     */
    protected static boolean isAjax(HttpServletRequest request) {
        boolean isAjax = request.getHeader("Accept").contains("json");
        if (isAjax) {
            return isAjax;
        }
        String ajaxRequest = request.getHeader("x-Requested-With");
        if (ajaxRequest != null && ajaxRequest.equals("XMLHttpRequest")) {
            isAjax = true;
        }
        return isAjax;
    }

    /**
     * 获取用户来源访问的协议和域名及端口
     * 如用户访问:https://www.haha.com:9000/merchant/regist.htm
     * 返回https://www.haha.com:9000
     */
    public static String getRequestHost(HttpServletRequest request) {
        return StringUtils.replace(request.getRequestURL().toString(), request.getRequestURI(), EMPTY);
    }

    /**
     * 302重定向跳转
     */
    public static void sendRedirect(HttpServletResponse response, String returnUrl) {
        response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
        response.setHeader("Location", returnUrl);
        response.setContentType("text/html; charset=UTF-8");
    }
}
